use std::collections::HashMap;

pub enum SegmentTag {
    SOF0 = 0xC0,            // Start of frame segment
    DHT = 0xC4,             // Define huffman table segment

    SOI = 0xD8,             // Start of image segment
    EOI = 0xD9,             // End of image segment
    SOS = 0xDA,             // Start of scan segment
    DQT = 0xDB,             // Define quantization table segment

    APP0 = 0xE0,            // Reserved for application segments

    INVALID = 0x00,
}

impl From<u8> for SegmentTag {
    fn from(s: u8) -> Self {
        match s {
            0xC0 => SegmentTag::SOF0,
            0xC4 => SegmentTag::DHT,

            0xD8 => SegmentTag::SOI,
            0xD9 => SegmentTag::EOI,
            0xDA => SegmentTag::SOS,
            0xDB => SegmentTag::DQT,

            0xE0 => SegmentTag::APP0,
            _ =>  SegmentTag::INVALID,
        }
    }
}

// The segment of reserved for application: 0xFFE0
#[derive(Debug, Default)]
pub struct App0Info {
    pub identifier:         [u8; 5],    // the identifier of the jpeg image
    pub version:            [u8; 2],    // the jpeg version
    pub density_units:      u8,         // 00: none; 01: the pixel/inc; 02: pixel/cm
    pub x_density:          u16,        // the horizontal density
    pub y_density:          u16,        // the vertical density
    pub x_thumbnail:        u8,         // the horizontal density of the thumbnail
    pub y_thumbnail:        u8,         // the vertical density of the thumbnail
    pub thumbnail_data:     Vec<u8>,    // the thumbnail data, the byte size: 3*x_thumbnail*y_thumbnail
}

// The segment of define quantization table: 0xFFDB
pub type DQuantable = [[f32; 64]; 4];

// The segment of define huffman table: 0xFFC4
#[derive(Debug, Default)]
pub struct DHuffmanTable {
    pub dc_table: [HashMap<(u8,u16),u8>; 2],     // the dc huffmant table
    pub ac_table: [HashMap<(u8,u16),u8>; 2],     // the ac huffmant table
}

#[derive(Debug, Default)]
pub struct ComInfoForSOF {
    pub com_id: u8,             // the component id
    pub h_sample_factor: u8,    // the horizontal sample factor
    pub v_sample_factor: u8,    // the vertical sample factor
    pub quantable_id: u8,       // the quantable id for the component
}

#[derive(Debug, Default)]
pub struct SOFInfo {
    pub precision_com: u8,  // the precision for the component in the jpeg
    pub height: u16,        // the height of the image
    pub width: u16,         // the width of the image
    pub num_com: u8,        // the number of components
    pub v_max_samples: u8,  // the maximum sample factor in vertical
    pub h_max_samples: u8,  // the maximum sample factor in horizontal
    pub coms: Vec<ComInfoForSOF>, // the component specifications parameters
}

#[derive(Debug, Default)]
pub struct ComInfoForSOS {
    pub com_id: u8,     // the component id
    pub dc_id: u8,      // the dc huffman table id for the component
    pub ac_id: u8,      // the ac huffman table id for the component
}

#[derive(Debug, Default)]
pub struct SOSInfo {
    pub num_com: u8,    // the number of components
    pub coms: Vec<ComInfoForSOS>,   // the component specifications parameters
}

#[derive(Debug)]
pub struct JPEGMetaData {
    pub quantable: DQuantable,          // the quantization table
    pub huffmantable: DHuffmanTable,    // the Huffman table
    pub sof: SOFInfo,                   // the SOF info
    pub sos: SOSInfo,                   // the SOS info
}

impl JPEGMetaData {
    pub fn new() -> Self {
        JPEGMetaData {
            quantable: [[0f32; 64];4],
            huffmantable: DHuffmanTable::default(),
            sof: SOFInfo::default(),
            sos: SOSInfo::default(),
        }
    }
}

pub type BlockInfo = [[f32; 8]; 8];

pub type ComBlockInfo = Vec<Vec<BlockInfo>>;

pub type MCUInfo = [ComBlockInfo; 3];   // there 3 color component unit in jpeg image

